/*
 * pixiv_down - CLI-based downloading tool for https://www.pixiv.net.
 * Copyright (C) 2024  Mio
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, version 3 of the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */
module app.logger;

import std.experimental.logger;
import app.config;
import app.vcs_tag;

void initializeLogger()
{
   import std.process : environment;
   import std.stdio : stderr;
   import std.uni : toLower;

   LogLevel level = LogLevel.warning;
   if ("PIXIV_DOWN_LOG_LEVEL" in environment) {
      const value = environment["PIXIV_DOWN_LOG_LEVEL"].toLower;
      switch(value) {
      case "all":
         level = LogLevel.all;
         break;
      case "trace":
         level = LogLevel.trace;
         break;
      case "info":
         level = LogLevel.info;
         break;
      case "debug":
         stderr.writeln("NOTE: The 'debug' log level is no longer supported.");
         stderr.writeln("      Falling back to 'warning'.");
         level = LogLevel.warning;
         break;
      case "warning":
         level = LogLevel.warning;
         break;
      case "error":
         level = LogLevel.error;
         break;
      case "fatal":
         level = LogLevel.fatal;
         break;
      default:
         stderr.writeln("Unknown log level: ", level);
         stderr.writeln("Supported values are: trace, info, warning, error, and fatal.");
         break;
      }
   }

   static if (__VERSION__ < 2101L) {
      sharedLog = new PDLogger(level);
   } else {
      sharedLog = cast(shared(PDLogger))new PDLogger(level);
   }

   logCompilationInfo();
}

private void logCompilationInfo()
{
   const bits = (void*).sizeof == 8 ? "64" : "32";
   version (linux)
      const system = "Linux";
   else version (Windows)
      const system = "Windows";
   else version (OSX)
      const system = "macOS";
   else
      const system = "Unknown";

   infof("pixiv_down %s (%s) started", PROJECT_VERSION_STRING, VCS_TAG);
   infof("Running on %s | %s-bit build | %s %,?d", system, bits, __VENDOR__, '.', __VERSION__);
}

class PDLogger : FileLogger {
   import std.concurrency : Tid;
   import std.datetime.systime : SysTime;
   import mlib.directories;

   private ProjectDirectories projectDirs;
   const string fileName;

   this(const LogLevel level = LogLevel.all) @safe
   {
      import std.file: exists, remove;
      import std.path: buildPath;

      projectDirs = getProjectDirectories(null, "YumeNeru Software", "pixiv_down");
      fileName = buildPath(projectDirs.stateDir, "pixiv_down.log");

      if (exists(fileName))
      {
         remove(fileName);
      }
      super(fileName, level);
   }

   override protected void beginLogMsg(string file, int line, string funcName,
      string prettyFuncName, string moduleName, LogLevel logLevel, Tid threadId,
      SysTime timestamp, Logger logger)
   {
      import std.conv : to;
      import std.datetime : DateTime;
      import std.format : formattedWrite;
      import std.string : toUpper;

      static if (__VERSION__ <= 2076L) {
         auto lt = this.file.lockingTextWriter();
      } else {
         auto lt = this.file_.lockingTextWriter();
      }
      auto dt = cast(DateTime)timestamp;
      formattedWrite(lt, "%s | %s | %5s | %-10s | ", dt.date.toISOExtString(),
         dt.timeOfDay.toISOExtString(), to!string(logLevel).toUpper, moduleName);
   }
}
